﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Reflection;
using System.Net.NetworkInformation;
using System.Threading;
using NetFwTypeLib;

namespace UpdateTool
{
    class UpdateTool
    {
        public static bool check_need_updates() {
            Dictionary<string, string> config = ReadConfig("Update.ini");
            string serverFileList = GetServerFileList(config);
            string localFileList = GenerateFileList(config);
            return serverFileList != localFileList;

        }
        static void Main(string[] args)
        {
             //RunSingleFileServer();
            string currentExePath = Assembly.GetEntryAssembly().Location;
            string currentExeName = Path.GetFileName(currentExePath);
            string currentExeDir = Directory.GetParent(currentExePath).FullName;
            if (currentExeName == "UpdateTool.exe")
            {
                RunTest(currentExePath, currentExeDir);
                Console.ReadKey();
            }
            else if (currentExeName == "UpdateServer.exe")
            {
                RunServer();
            }   
            else if (currentExeName == "SingleFileServer.exe")
            {
                RunSingleFileServer();
            }
            else if (currentExeName == "UpdateClient.exe")
            {
                RunClient();
                Console.ReadKey();
            }
            else if (currentExeName == "Test.exe")
            {
                Console_WriteLine("我扮演业务程序");
                Process.Start(new ProcessStartInfo
                {
                    FileName = Path.Combine(currentExeDir, "UpdateClient.exe"),
                    WorkingDirectory = currentExeDir,
                });

                Console.ReadKey();
                Console.WriteLine("hello world");
                Console.ReadKey();
                
            }
        }
        private static readonly string logFilePath = "UpdateTool.log";

        private static void Console_WriteLine(string message)
        {
            Console.WriteLine(message);
            LogToFile($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}\r\n");
        }

        private static void Console_Write(string message)
        {
            Console.Write(message);
            LogToFile(message);
        }

        private static void LogToFile(string message)
        {
            try
            {
                File.AppendAllText(logFilePath, message);
                
            }
            catch (Exception ex)
            {
                Console.WriteLine($"写入日志文件时发生错误: {ex.Message}");
            }
        }
        private static void RunTest(string currentExePath, string currentExeDir)
        {
            Console_WriteLine("我扮演测试员");

            string server_test_dir = Path.Combine(currentExeDir, "服务端测试");
            string client_test_dir = Path.Combine(currentExeDir, "客户端测试");
            File.Copy(currentExePath, Path.Combine(server_test_dir, "SingleFileServer.exe"), true);
            File.Copy(currentExePath, Path.Combine(server_test_dir, "UpdateServer.exe"), true);
            File.Copy(currentExePath, Path.Combine(client_test_dir, "UpdateClient.exe"), true);
            File.Copy(currentExePath, Path.Combine(server_test_dir, "Test.exe"), true);
            File.Copy(currentExePath, Path.Combine(client_test_dir, "Test.exe"), true);

            string text=File.ReadAllText(Path.Combine(currentExeDir, "Update.ini")).Replace("192.168.XXX.XXX", GetNativeIPv4Address());
            File.WriteAllText(Path.Combine(currentExeDir, "Update.ini"),text);
            File.Copy(Path.Combine(currentExeDir, "Update.ini"), Path.Combine(server_test_dir, "Update.ini"), true);
            File.Copy(Path.Combine(currentExeDir, "Update.ini"), Path.Combine(client_test_dir, "Update.ini"), true);
            Console_WriteLine("测试员 复制文件完成");
            Thread.Sleep(3000);

            Process.Start(new ProcessStartInfo
            {
                FileName = Path.Combine(server_test_dir, "UpdateServer.exe"),
                WorkingDirectory = server_test_dir,
            });
            Console_WriteLine("测试员 启动了服务端");
            Thread.Sleep(3000);
            Process.Start(new ProcessStartInfo
            {
                FileName = Path.Combine(client_test_dir, "Test.exe"),
                WorkingDirectory = client_test_dir,
            });
            Console_WriteLine("测试员 启动了业务程序");
        }

        public static string GetNativeIPv4Address()
        {
            List<string> arr = new List<string>();
            NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
            foreach (NetworkInterface networkInterface in networkInterfaces)
            {
                IPInterfaceProperties properties = networkInterface.GetIPProperties();
                foreach (UnicastIPAddressInformation address in properties.UnicastAddresses)
                {
                    if (address.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                    {
                        string ip = address.Address.ToString();
                        if (ip != "127.0.0.1")
                        {
                            arr.Add(ip);
                        }
                    }
                }
            }

            int length = arr.Count;
            if (length == 0)
            {
                return "127.0.0.1";
            }
            if (length == 1)
            {
                return arr[0];
            }
            if (length > 1)
            {
                foreach (string ip in arr)
                {
                    if (ip.StartsWith("192."))
                    {
                        return ip;
                    }
                }
            }
            return null;
        }
        private static void RunServer()
        {
            Console_WriteLine("--更新服务器准备启动\n\n--读取Update.ini");

            Dictionary<string, string> config = ReadConfig("Update.ini");
            foreach (string key in config.Keys)
            {
                Console_Write(key);
                Console_Write("=");
                Console_Write(config[key]);
                Console_Write("\r\n");
            }
            int port = int.Parse(config["listening_port"]);
            CreateFirewallRule(port);
            TcpListener server = new TcpListener(IPAddress.Any, port);
            Console_WriteLine("");
            Console_WriteLine("--获取服务器地址");
            Console_WriteLine($"http://{GetNativeIPv4Address()}:{port}");
            Console_WriteLine("");
            Console_WriteLine("--计算本地文件MD5");
            string csv = GenerateFileList(config);
            Console_WriteLine(csv);
            try
            {
                server.Start();
                Console_WriteLine("--准备就绪 等待连接");
                Console_WriteLine("");

                byte[] csv_bytes = Encoding.UTF8.GetBytes(csv);
                while (true)
                {
                    TcpClient client = server.AcceptTcpClient();
                    // 为每个线程创建独立的 buffer
                    byte[] buffer = new byte[1024];
                    // 将处理客户端连接的操作加入线程池队列
                    ThreadPool.QueueUserWorkItem(HandleClient, new object[] { client, buffer, csv_bytes });
                }
            }
            finally
            {
                server.Stop();
            }
        }

        private static void HandleClient(object state)
        {
            object[] args = (object[])state;
            TcpClient client = (TcpClient)args[0];
            byte[] buffer = (byte[])args[1];
            byte[] csv_bytes = (byte[])args[2];
            try
            {
                NetworkStream stream = client.GetStream();
                int bytesRead = stream.Read(buffer, 0, buffer.Length);
                string request = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                string clientIp = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
                Console_Write($"{DateTime.Now.ToString("MM-dd HH:mm:ss")} from {clientIp}: {request.Replace("\n", "\\n").Replace("\r", "\\r")}");
                if (request.StartsWith("GET_FILE_LIST"))
                {
                    stream.Write(csv_bytes, 0, csv_bytes.Length);
                    Console_WriteLine($" OK");
                }
                else if (request.StartsWith("GET_FILE="))
                {
                    string filePath = request.Substring("GET_FILE=".Length).Trim();
                    if (File.Exists(filePath))
                    {
                        using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                        {
                            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0)
                            {
                                stream.Write(buffer, 0, bytesRead);
                            }
                            Console_WriteLine($" OK");
                        }
                    }
                    else
                    {
                        Console_WriteLine($" ERROR: File not found.");
                    }
                }
                else
                {
                    Console_WriteLine($" ERROR: Unknown request");
                }
            }
            catch (Exception ex)
            {
                Console_WriteLine($"处理客户端连接时发生错误: {ex.Message}");
            }
            finally
            {
                client.Close();
            }
        }
        private static void RunClient()
        {
            Console_WriteLine("--更新客户端准备启动\n\n--读取Update.ini");
            Dictionary<string, string> config = ReadConfig("Update.ini");
            foreach (string key in config.Keys)
            {
                Console_Write(key);
                Console_Write("=");
                Console_Write(config[key]);
                Console_Write("\r\n");
            }
            string business_app = config["business_app"];
            Console_WriteLine("--获取服务器清单");
            string serverFileList = GetServerFileList(config);
            if (serverFileList == null) {
                Console_WriteLine($"--获取失败 需检查服务端地址server_ip_port={config["server_ip_port"]}是否填写正确");
                return;
            }
            Console_WriteLine(serverFileList);
            Console_WriteLine("--计算本地文件MD5");
            string localFileList = GenerateFileList(config);
            Console_WriteLine(localFileList);

            if (serverFileList == localFileList)
            {
                Console_WriteLine("--检查结果:无需更新");
            }
            else
            {
                Console_WriteLine("--检查结果:需要更新");
                StopProcess(business_app);
                Console_WriteLine("--开始更新");
                UpdateFiles(serverFileList, localFileList, config);

                // 启动主程序
                Console_WriteLine("--更新完成!!");
                string currentExePath = Assembly.GetEntryAssembly().Location;
                string currentExeDir = Directory.GetParent(currentExePath).FullName;
                string mainApp_path = Path.Combine(currentExeDir, business_app);
                if (File.Exists(mainApp_path))
                {
                    Process.Start(mainApp_path);
                    Console_WriteLine("--启动主程序" + mainApp_path);
                }
                else
                {
                    Console_WriteLine("--主程序未找到:" + mainApp_path);
                }

            }
        }

        private static string GetServerFileList(Dictionary<string, string> config)
        {
            string server_ip_port = config["server_ip_port"];
            string[] parts = server_ip_port.Trim().Split(':');
            string ipAddress = parts[0];
            int port = int.Parse(parts[1]);
            TcpClient client = new TcpClient();

            try
            {
                // 设置连接超时时间为 10 秒
                IAsyncResult result = client.BeginConnect(ipAddress, port, null, null);
                bool success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(10));
                if (!success)
                {
                    return null;
                }
                client.EndConnect(result);

                NetworkStream stream = client.GetStream();
                stream.ReadTimeout = 10000; // 设置读取超时时间为 10 秒

                string request = "GET_FILE_LIST\n";
                byte[] requestBytes = Encoding.UTF8.GetBytes(request);
                stream.Write(requestBytes, 0, requestBytes.Length);
                stream.Flush();

                // 动态读取数据
                var memoryStream = new System.IO.MemoryStream();
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    memoryStream.Write(buffer, 0, bytesRead);
                }

                return Encoding.UTF8.GetString(memoryStream.ToArray());
            }
            catch (Exception)
            {
                return null;
            }
            finally
            {
                client.Close();
            }
        }

        private static string GenerateFileList(Dictionary<string, string> config)
        {
            string ignore_regexp = config["ignore_regexp"];
            string[] ignorePatterns = ignore_regexp.Split(';');
            ignorePatterns = Array.FindAll(ignorePatterns, p => !string.IsNullOrEmpty(p));
            List<string> files = new List<string>();
            string currentDir = Directory.GetCurrentDirectory();
            foreach (string filePath in Directory.EnumerateFiles(currentDir, "*", SearchOption.AllDirectories))
            {
                string relativePath = GetRelativePath(currentDir, filePath);
                if (ShouldIgnore(relativePath, ignorePatterns))
                {
                    continue;
                }
                string md5 = CalculateMD5(filePath);
                files.Add($"{relativePath};{md5}\r\n"); // 修改分隔符为分号
            }
            files.Sort();
            return string.Join("", files.ToArray());
        }

        private static bool ShouldIgnore(string path, string[] patterns)
        {
            foreach (string pattern in patterns)
            {
                if (Regex.IsMatch(path, pattern))
                {
                    return true;
                }
            }
            return false;
        }

        private static string CalculateMD5(string filePath)
        {
            using (FileStream file = File.OpenRead(filePath))
            {
                using (MD5 md5 = MD5.Create())
                {
                    byte[] hashBytes = md5.ComputeHash(file);
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < hashBytes.Length; i++)
                    {
                        sb.Append(hashBytes[i].ToString("x2"));
                    }
                    return sb.ToString();
                }
            }
        }

        static Dictionary<string, string> ReadConfig(string configFile)
        {
            Dictionary<string, string> config = new Dictionary<string, string>();
            if (File.Exists(configFile))
            {
                string[] lines = File.ReadAllLines(configFile);
                foreach (string line in lines)
                {
                    if (line.Contains("="))
                    {
                        string[] parts = line.Split('=');
                        if (parts.Length >= 2)
                        {
                            config[parts[0].Trim()] = parts[1].Trim();
                        }
                    }
                }
            }
            return config;
        }

        private static void StopProcess(string processName)
        {
            Process[] processes = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(processName));
            Console_WriteLine($"{processName}发现{processes.Length}个 正在运行     尝试关闭...");
            foreach (Process process in processes)
            {
                try
                {
                    process.Kill();
                    process.WaitForExit();
                }
                catch (Exception ex)
                {
                    Console_WriteLine($"Error stopping process {processName}: {ex.Message}");
                }
            }
        }

        private static void UpdateFiles(string serverFileList, string localFileList, Dictionary<string, string> config)
        {

            string ignore_regexp = config["ignore_regexp"];
            string[] ignorePatterns = ignore_regexp.Split(';');
            ignorePatterns = Array.FindAll(ignorePatterns, p => !string.IsNullOrEmpty(p));
            string currentDir = Directory.GetCurrentDirectory();
            Dictionary<string, string> serverFiles = ParseFileList(serverFileList);
            Dictionary<string, string> localFiles = ParseFileList(localFileList);

            // 删除本地多余文件
            foreach (string localPath in new List<string>(localFiles.Keys))
            {
                if (!serverFiles.ContainsKey(localPath) && !ShouldIgnore(localPath, ignorePatterns))
                {
                    string fullPath = Path.Combine(currentDir, localPath);
                    if (File.Exists(fullPath))
                    {
                        File.Delete(fullPath);
                        Console_WriteLine($"Deleted file {fullPath}");
                    }
                }
            }

            // 更新或新增文件
            foreach (KeyValuePair<string, string> serverEntry in serverFiles)
            {
                string relativePath = serverEntry.Key;
                if (ShouldIgnore(relativePath, ignorePatterns))
                {
                    continue;
                }
                string localMD5 = localFiles.ContainsKey(relativePath) ? localFiles[relativePath] : null;
                if (localMD5 != serverEntry.Value)
                {
                    string fullPath = Path.Combine(currentDir, relativePath);
                    string directory = Path.GetDirectoryName(fullPath);
                    if (!Directory.Exists(directory))
                    {
                        Directory.CreateDirectory(directory);
                    }
                    DownloadFile(relativePath, fullPath, config);
                    Console_WriteLine($"Updated file {fullPath}");
                }
            }
        }

        private static Dictionary<string, string> ParseFileList(string fileList)
        {
            Dictionary<string, string> files = new Dictionary<string, string>();
            string[] lines = fileList.Split(new[] { '\n', '\r' });
            lines = Array.FindAll(lines, l => !string.IsNullOrEmpty(l));
            foreach (string line in lines)
            {
                int index = line.IndexOf(';'); // 修改分隔符为分号
                if (index != -1)
                {
                    string key = line.Substring(0, index).Trim();
                    string value = line.Substring(index + 1).Trim();
                    files[key] = value;
                }
            }
            return files;
        }

        private static void DownloadFile(string relativePath, string fullPath, Dictionary<string, string> config)
        {
            string server_ip_port = config["server_ip_port"];
            string[] parts = server_ip_port.Trim().Split(':');
            string ipAddress = parts[0];
            int port = int.Parse(parts[1]);
            TcpClient client = new TcpClient();
            try
            {
                client.Connect(ipAddress, port);
                NetworkStream stream = client.GetStream();
                string request = $"GET_FILE={relativePath}\n";
                byte[] requestBytes = Encoding.UTF8.GetBytes(request);
                stream.Write(requestBytes, 0, requestBytes.Length);

                using (FileStream fileStream = File.Create(fullPath))
                {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        fileStream.Write(buffer, 0, bytesRead);
                    }
                }
            }
            finally
            {
                client.Close();
            }
        }

        private static string GetRelativePath(string fromPath, string toPath)
        {
            if (string.IsNullOrEmpty(fromPath)) throw new ArgumentNullException("fromPath");
            if (string.IsNullOrEmpty(toPath)) throw new ArgumentNullException("toPath");

            Uri fromUri = new Uri(AppendDirectorySeparatorChar(fromPath));
            Uri toUri = new Uri(toPath);

            if (fromUri.Scheme != toUri.Scheme) { return toPath; }

            Uri relativeUri = fromUri.MakeRelativeUri(toUri);
            string relativePath = Uri.UnescapeDataString(relativeUri.ToString());

            if (toUri.Scheme.Equals("file", StringComparison.InvariantCultureIgnoreCase))
            {
                relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
            }

            return relativePath;
        }

        private static string AppendDirectorySeparatorChar(string path)
        {
            if (!Path.HasExtension(path) &&
                !path.EndsWith(Path.DirectorySeparatorChar.ToString()))
            {
                return path + Path.DirectorySeparatorChar;
            }

            return path;
        }
        /// <summary>
        /// 为指定端口号创建防火墙规则
        /// </summary>
        /// <param name="port"></param>
        private static void CreateFirewallRule(int port)
        {
            string ruleName = $"UpdateTool的自定义规则{port}";
            try
            {
                // 创建防火墙管理对象
                Type type = Type.GetTypeFromProgID("HNetCfg.FwPolicy2");
                INetFwPolicy2 fwPolicy2 = (INetFwPolicy2)Activator.CreateInstance(type);

                // 检查规则是否已存在
                bool ruleExists = false;
                foreach (INetFwRule rule in fwPolicy2.Rules)
                {
                    if (rule.Name == ruleName)
                    {
                        ruleExists = true;
                        Console.WriteLine($"--防火墙规则 '{ruleName}' 已存在，无需重复创建。");

                        // 检查现有规则配置是否需要更新
                        bool needsUpdate = false;
                        if (rule.Description != $"允许访问端口 {port}")
                        {
                            rule.Description = $"允许访问端口 {port}";
                            needsUpdate = true;
                        }
                        if (rule.Protocol != (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP)
                        {
                            rule.Protocol = (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP;
                            needsUpdate = true;
                        }
                        if (rule.LocalPorts != port.ToString())
                        {
                            rule.LocalPorts = port.ToString();
                            needsUpdate = true;
                        }
                        if (rule.Action != NET_FW_ACTION_.NET_FW_ACTION_ALLOW)
                        {
                            rule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW;
                            needsUpdate = true;
                        }
                        if (rule.Profiles != fwPolicy2.CurrentProfileTypes)
                        {
                            rule.Profiles = fwPolicy2.CurrentProfileTypes;
                            needsUpdate = true;
                        }
                        if (!rule.Enabled)
                        {
                            rule.Enabled = true;
                            needsUpdate = true;
                        }

                        if (needsUpdate)
                        {
                            Console.WriteLine($"--已更新现有防火墙规则 '{ruleName}' 的配置。");
                        }

                        return;
                    }
                }

                // 创建新的防火墙规则对象
                INetFwRule2 inboundRule = (INetFwRule2)Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwRule"));

                // 设置规则名称
                inboundRule.Name = ruleName;
                // 设置规则描述
                inboundRule.Description = $"允许访问端口 {port}";
                // 设置规则应用的协议为 TCP
                inboundRule.Protocol = (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP;
                // 设置规则应用的本地端口
                inboundRule.LocalPorts = port.ToString();
                // 设置规则操作类型为允许
                inboundRule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW;
                // 设置规则应用范围为所有网络配置文件
                inboundRule.Profiles = fwPolicy2.CurrentProfileTypes;
                // 设置规则启用状态
                inboundRule.Enabled = true;

                // 将规则添加到防火墙策略中
                fwPolicy2.Rules.Add(inboundRule);
                Console.WriteLine($"--已在防火墙中开放端口 {port}。");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"--创建防火墙规则时出错: {ex.Message}{ex.StackTrace}");
            }
        }
        /// <summary>
        /// 生产环境的电脑第一次使用 但是还是不想用u盘
        /// </summary>
        private static void RunSingleFileServer()
        {
            Dictionary<string, string> config = ReadConfig("Update.ini");
            int port = int.Parse(config["browser_download_listening_port"].Trim());
            string filePath = config["browser_download_file"].Trim();
           
            // 要共享的文件路径
            // 监听的 URL，这里使用 8080 端口，可根据需要修改
            string url = $"http://*:{port}/";

            try
            {
                HttpListener listener = new HttpListener();
                listener.Prefixes.Add(url);
                listener.Start();

                // 获取本地 IP 地址
                string localIp = GetNativeIPv4Address();
                string fullUrl = $"http://{localIp}:{port}";
                Console.WriteLine($"--请把准备好{Path.GetFileName(filePath)}文件放在{Path.GetFullPath(filePath)}");
                CreateFirewallRule(port);
                Console.WriteLine($"--单文件服务器已启动  局域网下的电脑可以在浏览器下载该文件{fullUrl}");

                while (true)
                {
                    HttpListenerContext context = listener.GetContext();
                    HttpListenerRequest request = context.Request;
                    HttpListenerResponse response = context.Response;
                    //// 打印请求者信息
                    //Console.WriteLine("----------------------------------------");
                    //Console.WriteLine($"新请求来自: {request.RemoteEndPoint}");
                    //Console.WriteLine($"时间: {DateTime.Now}");
                    //Console.WriteLine($"HTTP方法: {request.HttpMethod}");
                    //Console.WriteLine($"请求URL: {request.Url}");
                    //Console.WriteLine($"用户代理: {request.UserAgent ?? "未提供"}");
                    //Console.WriteLine($"语言: {string.Join(", ", request.UserLanguages ?? new string[0])}");
                    //Console.WriteLine($"内容类型: {request.ContentType ?? "未指定"}");
                    //Console.WriteLine($"内容长度: {request.ContentLength64} 字节");
                    //Console.WriteLine("请求头:");
                    //foreach (string header in request.Headers)
                    //{
                    //    Console.WriteLine($"  {header}: {request.Headers[header]}");
                    //}
                    new Thread(() => {
                        try
                        {
                            if (request.HttpMethod == "HEAD") {
                                response.StatusCode = (int)HttpStatusCode.OK;
                                response.OutputStream.Close();
                            } else  {
                                Respond(filePath, response);
                            }
                            Console.WriteLine($"{DateTime.Now} 来自: {request.RemoteEndPoint} {request.HttpMethod} 成功");

                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"{ex.Message} {ex.StackTrace}");
                        }
                        finally {
                            response.Close();
                        }

                    }).Start();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"An error occurred: {ex.Message}");
            }
        }

        private static void Respond(string filePath, HttpListenerResponse response)
        {
            if (File.Exists(filePath))
            {
                response.ContentType = "application/octet-stream";
                // 处理文件名，去除无效字符
                string fileName = Path.GetFileName(filePath);
                fileName = Regex.Replace(fileName, @"[^\w\.@-]", "_");
                // 对文件名进行编码
                string encodedFileName = Uri.EscapeDataString(fileName);
                response.AddHeader("Content-Disposition", $"attachment; filename*=UTF-8''{encodedFileName}");
                response.ContentLength64 = new FileInfo(filePath).Length;

                using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        response.OutputStream.Write(buffer, 0, bytesRead);
                    }
                }
                response.OutputStream.Close();
            }
            else
            {
                response.StatusCode = (int)HttpStatusCode.NotFound;
                byte[] buffer = System.Text.Encoding.UTF8.GetBytes("File not found:" + Path.GetFullPath(filePath));
                response.ContentLength64 = buffer.Length;
                Stream output = response.OutputStream;
                output.Write(buffer, 0, buffer.Length);
                output.Close();
            }
        }
    }
}